package com.gomoku.backend.consumer;

import com.alibaba.fastjson2.JSONObject;
import com.gomoku.backend.consumer.utils.Game;
import com.gomoku.backend.mapper.RecordMapper;
import com.gomoku.backend.mapper.UserMapper;
import com.gomoku.backend.pojo.User;
import com.gomoku.backend.utils.JwtAuthentication;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
import org.springframework.web.client.RestTemplate;

import javax.websocket.*;
import javax.websocket.server.PathParam;
import javax.websocket.server.ServerEndpoint;
import java.io.IOException;
import java.util.concurrent.ConcurrentHashMap;

@Component
@ServerEndpoint("/websocket/{token}")  // 注意不要以'/'结尾
public class WebSocketServer {
    private  Session session = null;//这个Session是websocket里面的包
    //每一个 new 的websocket都只有一个users 全局变量
    public final static ConcurrentHashMap<Integer, WebSocketServer> users = new ConcurrentHashMap<>();
    private User user;
    public static UserMapper userMapper;
    public static RecordMapper recordMapper;
    public static RestTemplate restTemplate;

    private final static String addPlayerUrl = "http://127.0.0.1:3001/player/add/";
    private final static String removePlayerUrl = "http://127.0.0.1:3001/player/remove/";

    @Autowired
    public void setUserMapper(UserMapper usermapper){
        WebSocketServer.userMapper = usermapper;
    }
    @Autowired
    public void setRecordMapper(RecordMapper recordMapper){WebSocketServer.recordMapper = recordMapper;}
    @Autowired
    public void setRestTemplate(RestTemplate restTemplate){
        WebSocketServer.restTemplate = restTemplate;
    }

    public Game game = null;
    @OnOpen
    public void onOpen(Session session, @PathParam("token") String token) throws IOException {
        // 建立连接
        this.session=session; //每个链接通过session来维护
        System.out.println("Connected to websocket!");
        int userId = JwtAuthentication.getUserId(token);
        //接下来是通过用户id查到用户信息
        this.user = userMapper.selectById(userId);
        if(this.user!=null){
            users.put(userId,this);
        }else{
            this.session.close();
        }

        System.out.println(users);
    }

    @OnClose
    public void onClose() {
        // 关闭链接
        System.out.println("Disconnected from websocket!");
        if(this.user!=null) {
            users.remove(this.user.getId());
        }
    }

    public static  void startAIGame(Integer userId,Integer botId){

        User a = userMapper.selectById(userId);
        Game game = new Game(16,16,a.getId(), botId,true);
        //这里防止用户匹配还未进入游戏界面时但和其他玩家匹配上，却此时出现意外退出链接
        if(users.get(a.getId())!=null)
            users.get(a.getId()).game = game;

        game.start();
        JSONObject respGame = new JSONObject();
        respGame.put("a_id",game.getPlayerA().getId());
        respGame.put("rows",game.getRows());
        respGame.put("cols",game.getCols());

        JSONObject respA = new JSONObject();
        respA.put("event","start-matching");
//        这个不需要，因为前端的pk 对手信息只存一份，在PK的时候存储
//        respA.put("opponent_username",b.getUsername());
//        respA.put("opponent_photo",b.getPhoto());
        respA.put("game",respGame);
        if(users.get(a.getId())!=null)
            users.get(a.getId()).sendMessage(respA.toJSONString());
    }
    public static void startGame(Integer aId,Integer bId){ //匹配完成之后返回两个玩家id，调用这个函数开始游戏
        User a = userMapper.selectById(aId);
        User b = userMapper.selectById(bId);

        Game game = new Game(16,16,a.getId(), b.getId(),false);
        //这里防止用户匹配还未进入游戏界面时但和其他玩家匹配上，却此时出现意外退出链接
        if(users.get(a.getId())!=null)
            users.get(a.getId()).game = game;
        if(users.get(b.getId())!=null)
            users.get(b.getId()).game = game;
        game.start();

        JSONObject respGame = new JSONObject();
        respGame.put("a_id",game.getPlayerA().getId());
        respGame.put("b_id",game.getPlayerB().getId());
        respGame.put("rows",game.getRows());
        respGame.put("cols",game.getCols());

        JSONObject respA = new JSONObject();
        respA.put("event","start-matching");
        respA.put("opponent_username",b.getUsername());
        respA.put("opponent_photo",b.getPhoto());
        respA.put("game",respGame);
        if(users.get(a.getId())!=null)
            users.get(a.getId()).sendMessage(respA.toJSONString());

        JSONObject respB = new JSONObject();
        respB.put("event","start-matching");
        respB.put("opponent_username",a.getUsername());
        respB.put("opponent_photo",a.getPhoto());
        respB.put("game",respGame);
        if(users.get(b.getId())!=null)
             users.get(b.getId()).sendMessage(respB.toJSONString());

    }
    public void startMatching(String bot_id){
        System.out.println("Connected success!");
        //这里前后端通讯格式为MultiValueMap,不用这个可能会报错
        MultiValueMap<String,String> data=new LinkedMultiValueMap<>();
        data.add("user_id",this.user.getId().toString());
        data.add("rating",this.user.getRating().toString());
        data.add("bot_id",bot_id);
        restTemplate.postForObject(addPlayerUrl,data,String.class);
    }

    public void stopMatching(){
        System.out.println("Disconnected!");
        MultiValueMap<String,String> data = new LinkedMultiValueMap<>();
        data.add("user_id",this.user.getId().toString());
        restTemplate.postForObject(removePlayerUrl,data,String.class);
    }
    public void move(Integer col,Integer row,Integer currentPlayer){
        //首先是判断一下当前的位置是否合法
        if(col <1 || col >this.game.getCols()-1 || row <1 || row>this.game.getRows())
            return;
        if(game.getBoard()[row][col] != 0)
            return;

        if(game.getPlayerA().getId().equals(user.getId()) || game.getPlayerB().getId().equals(user.getId())){ //只要是保证是当前链接的user就可以
            //System.out.println(col+" "+row);
            game.getBoard()[row][col] = game.getCurrentPlayer();

            if(game.getPlayerA().getId().equals(user.getId()) && currentPlayer == 1){
                game.setPlayerA(col,row);
                game.setNextStepA(true); //这个是不是可以把这个优化掉
            }else if(game.getPlayerB().getId().equals(user.getId()) && currentPlayer == 2){
                game.setPlayerB(col,row);
                game.setNextStepB(true);
            }
        }
    }
    @OnMessage
    public void onMessage(String message, Session session) {
        // 后端接受前端Client消息
        //System.out.println("Received message: ");
        //前端通过send来发送一个信息
        JSONObject data = JSONObject.parseObject(message); //把这个字符串Json解析出来
        String event = data.getString("event");
        if("start-matching".equals(event)){
            startMatching(data.getString("bot_id"));
        } else if("stop-matching".equals(event)){
            stopMatching();
        } else if("move".equals(event)){
            move(data.getInteger("col"),data.getInteger("row"),data.getInteger("currentPlayer"));
        }
    }

    @OnError
    public void onError(Session session, Throwable error) {
        error.printStackTrace();
    }

    //向前端发送信息，
    //例如 users.get(b.getId()) //通过ID取得 websocket
    //                      .sendMessage(respB.toJSONString());
    public void sendMessage(String message) {
        synchronized (this.session){ //异步通信需要加锁
            try {
                this.session.getBasicRemote().sendText(message); //后端向前端发送message，封装到data里面
            } catch (IOException e){
                e.printStackTrace();
            }
        }
    }
}